package com.controller;

import com.model.TCPThread;
import com.model.UDPThread;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ScanAction implements ActionListener {
    private int[] secIP = new int[5];   // IP地址段
    private String hostName = "";       // 域名
    private int[] port = new int[2];    // 端口
    private int numOfThreads;           // 线程数
    private ExecutorService executorService= Executors.newFixedThreadPool(200);
    @Override
    public void actionPerformed(ActionEvent e) {
        InitialThread.logger.debug("{}: \"开始扫描\"按钮动作监听器", this.getClass().getSimpleName());

        // 使用IP地址进行扫描
        if (InitialThread.getAddrScanJRadio1().isSelected()) {
            // 验证IP地址的有效性和正确性
            for (int i = 0; i < InitialThread.getIpAddrTextField().length; i++) {
                try {
                    secIP[i] = Integer.parseInt(InitialThread.getIpAddrTextField()[i].getText());
                    checkAddressRange(secIP[i]);
                } catch (NumberFormatException | InputMismatchException e1) {
                    InitialThread.logger.debug("错误:IP地址应为0-255的整数--第{}个输入框内容为{}", i + 1, InitialThread.getIpAddrTextField()[i].getText());

                    String msg = "错误:IP地址应为0-255的整数--"
                            + "第".intern() + (i + 1)
                            + "个输入框内容为:" + InitialThread.getIpAddrTextField()[i].getText();

                    JOptionPane.showMessageDialog(InitialThread.main, msg, "IP地址错误", JOptionPane.ERROR_MESSAGE);

                    return;
                }
            }
            // 一种特殊情况的处理: 末段IP地址的结束地址大于起始地址
            if (secIP[4] < secIP[3]) {
                InitialThread.logger.debug("错误:末段IP地址的结束地址应大于等于起始地址--起始地址为{},终止地址为{}", secIP[3], secIP[4]);

                String msg = "错误:末段IP地址的结束地址应大于等于起始地址--起始地址为"
                        + secIP[3] + ",终止地址为" + secIP[4];

                JOptionPane.showMessageDialog(InitialThread.main, msg, "IP地址错误", JOptionPane.ERROR_MESSAGE);

                return;
            }
        } else if (InitialThread.domeScanJRadio1.isSelected()) {
            try {
                InetAddress host = InetAddress.getByName(InitialThread.domainNameTextField.getText());
                hostName = host.getHostName();
            } catch (UnknownHostException e1) {
                InitialThread.logger.debug("错误的域名,或主机不可达");

                String msg = "错误: 域名错误,或主机不可达";

                JOptionPane.showMessageDialog( InitialThread.main, msg, "域名错误或主机不可达", JOptionPane.ERROR_MESSAGE);

                return;
            }

        } else {
            throw new RuntimeException("扫描方式出现运行时错误");
        }

        // 验证端口的有效性和正确性
        for (int i = 0; i < port.length; i++) {
            try {
                port[i] = Integer.parseInt(InitialThread.portTextField[i].getText());
                checkPortRange(port[i]);
            } catch (NumberFormatException | InputMismatchException e1) {
                InitialThread.logger.debug("错误:端口地址应为0-65535的整数--第{}个输入框内容为{}", i + 1, InitialThread.portTextField[i].getText());

                String msg = "错误:端口地址应为0-65535的整数--第"+(i+1)+"个输入框内容为"+InitialThread.portTextField[i].getText();

                JOptionPane.showMessageDialog( InitialThread.main, msg, "端口地址错误", JOptionPane.ERROR_MESSAGE);

                return;
            }
        }

        // 验证线程数的有效性和正确性
        try {
            numOfThreads = Integer.parseInt(InitialThread.numOfThreadsTextField.getText());
            checkThreadsNumRange(numOfThreads);
        } catch (NumberFormatException | InputMismatchException e1) {
            InitialThread.logger.debug("错误:线程数应为0-200的整数--输入框内容为{}", InitialThread.numOfThreadsTextField.getText());

            String msg = "错误:线程数应为0-200的整数--输入框内容为"+InitialThread.numOfThreadsTextField.getText();

            JOptionPane.showMessageDialog( InitialThread.main, msg, "线程数量错误", JOptionPane.ERROR_MESSAGE);

            return;
        }

        /*
         * 验证无误后,给TCPThread类参数赋值
         * 1. String scanType
         * 2. int[] secIP / String hostName
         * 3. int[] port
         * 4. int numOfThreads
         */
        if (InitialThread.addrScanJRadio1.isSelected()) {
            if(InitialThread.TCPSelectJRadio2.isSelected()){
                System.out.println(1);
                TCPThread.scanType = TCPThread.ADDRESS_SCAN;
                TCPThread.secIP = secIP;

                InitialThread.logger.debug("按IP地址进行扫描");
                InitialThread.logger.debug("目标IP地址为{}", Arrays.toString(TCPThread.secIP));

                TCPThread.port = port;
                TCPThread.numOfThreads = numOfThreads;
            }

            else if(InitialThread.UDPSelectJRadio2.isSelected()){
                System.out.println(2);
                UDPThread.scanType = UDPThread.ADDRESS_SCAN;
                UDPThread.secIP = secIP;

                InitialThread.logger.debug("按IP地址进行扫描");
                InitialThread.logger.debug("目标IP地址为{}", Arrays.toString(TCPThread.secIP));

                UDPThread.port = port;
                UDPThread.numOfThreads = numOfThreads;
            }


        } else {
            if(InitialThread.TCPSelectJRadio2.isSelected()){
                System.out.println(1);
                TCPThread.scanType = TCPThread.DOMAINNAME_SCAN;
                TCPThread.hostName = hostName;

                TCPThread.port = port;
                TCPThread.numOfThreads = numOfThreads;
            }

            else if(InitialThread.UDPSelectJRadio2.isSelected()){
                System.out.println(2);
                UDPThread.scanType = UDPThread.DOMAINNAME_SCAN;
                UDPThread.hostName = hostName;

                UDPThread.port = port;
                UDPThread.numOfThreads = numOfThreads;
            }

            InitialThread.logger.debug("按域名进行扫描");
            InitialThread.logger.debug("目标主机域名为{}", hostName);
        }


        InitialThread.logger.debug("目标主机端口范围为{}", Arrays.toString(port));
        InitialThread.logger.debug("最大启动线程数为{}", numOfThreads);

        // 启动扫描
        if (InitialThread.submitBtn.isEnabled()) {
            InitialThread.submitBtn.setEnabled(!InitialThread.submitBtn.isEnabled());
            if (InitialThread.resultTextArea.getText() != null)
                InitialThread.resultTextArea.setText(null);
        }

        if(InitialThread.TCPSelectJRadio2.isSelected()){
            for (int i = 0; i < numOfThreads; i++)
                executorService.execute( new TCPThread("T" + i, i));
        }
        else if(InitialThread.UDPSelectJRadio2.isSelected()){
            //对于UDP设置障栅
            CyclicBarrier barrier = new CyclicBarrier(numOfThreads + 1);
            for (int i = 0; i < numOfThreads; i++)
                executorService.execute( new UDPThread("T" + i, i,barrier));
        }
    }

    // 检查IP地址的范围
    private void checkAddressRange(int ip) throws InputMismatchException {
        if (ip < 0 || ip > 255)
            throw new InputMismatchException();
    }

    // 检查端口的范围
    private void checkPortRange(int port) throws InputMismatchException {
        if (port < 0 || port > 65535)
            throw new InputMismatchException();
    }

    // 检查线程数的范围
    private void checkThreadsNumRange(int numOfThreads) throws InputMismatchException {
        if (numOfThreads < 0 || numOfThreads > 200)
            throw new InputMismatchException();
    }
}